/* GLUCo - OpenGL Unified Code
 * 
 * Copyright (c) 2007 Pedro Leite.
 * 
 * Written by Pedro Leite, <pedro.leite@gmail.com>
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#include <stdlib.h>
#include <stdio.h>

#include "window.h"
#include "window_manager.h"

GLfloat	g_rtri = 0.0f;
GLfloat	g_rquad = 0.0f;

void window_init_func(void) {
	glShadeModel(GL_SMOOTH);
    glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
    glClearDepth(1.0f);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_COLOR_MATERIAL);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
}

void window_display_func(void) {
	static int frames = 0;
	static int elapsedTime = 0;
	static int currTime = 0;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
	glPushMatrix();
	glTranslatef(-1.5f,0.0f,-6.0f);						// Move Left 1.5 Units And Into The Screen 6.0
	glRotatef(g_rtri,0.0f,1.0f,0.0f);					// Rotate The Triangle On The Y Axis
	glBegin(GL_TRIANGLES);								// Start Drawing A Triangle
		glColor3f(1.0f,0.0f,0.0f);						// Red
		glVertex3f( 0.0f, 1.0f, 0.0f);					// Top Of Triangle (Front)
		glColor3f(0.0f,1.0f,0.0f);						// Green
		glVertex3f(-1.0f,-1.0f, 1.0f);					// Left Of Triangle (Front)
		glColor3f(0.0f,0.0f,1.0f);						// Blue
		glVertex3f( 1.0f,-1.0f, 1.0f);					// Right Of Triangle (Front)
		glColor3f(1.0f,0.0f,0.0f);						// Red
		glVertex3f( 0.0f, 1.0f, 0.0f);					// Top Of Triangle (Right)
		glColor3f(0.0f,0.0f,1.0f);						// Blue
		glVertex3f( 1.0f,-1.0f, 1.0f);					// Left Of Triangle (Right)
		glColor3f(0.0f,1.0f,0.0f);						// Green
		glVertex3f( 1.0f,-1.0f, -1.0f);					// Right Of Triangle (Right)
		glColor3f(1.0f,0.0f,0.0f);						// Red
		glVertex3f( 0.0f, 1.0f, 0.0f);					// Top Of Triangle (Back)
		glColor3f(0.0f,1.0f,0.0f);						// Green
		glVertex3f( 1.0f,-1.0f, -1.0f);					// Left Of Triangle (Back)
		glColor3f(0.0f,0.0f,1.0f);						// Blue
		glVertex3f(-1.0f,-1.0f, -1.0f);					// Right Of Triangle (Back)
		glColor3f(1.0f,0.0f,0.0f);						// Red
		glVertex3f( 0.0f, 1.0f, 0.0f);					// Top Of Triangle (Left)
		glColor3f(0.0f,0.0f,1.0f);						// Blue
		glVertex3f(-1.0f,-1.0f,-1.0f);					// Left Of Triangle (Left)
		glColor3f(0.0f,1.0f,0.0f);						// Green
		glVertex3f(-1.0f,-1.0f, 1.0f);					// Right Of Triangle (Left)
	glEnd();											// Done Drawing The Pyramid
    glPopMatrix();                                      // Restore Modelview Matrix 
	glTranslatef(1.5f,0.0f,-7.0f);						// Move Right 1.5 Units And Into The Screen 7.0
	glRotatef(g_rquad,1.0f,0.0f,0.0f);					// Rotate The Quad On The X Axis 
	glBegin(GL_QUADS);									// Draw A Quad
		glColor3f(0.0f,1.0f,0.0f);						// Set The Color To Blue
		glVertex3f( 1.0f, 1.0f,-1.0f);					// Top Right Of The Quad (Top)
		glVertex3f(-1.0f, 1.0f,-1.0f);					// Top Left Of The Quad (Top)
		glVertex3f(-1.0f, 1.0f, 1.0f);					// Bottom Left Of The Quad (Top)
		glVertex3f( 1.0f, 1.0f, 1.0f);					// Bottom Right Of The Quad (Top)
		glColor3f(1.0f,0.5f,0.0f);						// Set The Color To Orange
		glVertex3f( 1.0f,-1.0f, 1.0f);					// Top Right Of The Quad (Bottom)
		glVertex3f(-1.0f,-1.0f, 1.0f);					// Top Left Of The Quad (Bottom)
		glVertex3f(-1.0f,-1.0f,-1.0f);					// Bottom Left Of The Quad (Bottom)
		glVertex3f( 1.0f,-1.0f,-1.0f);					// Bottom Right Of The Quad (Bottom)
		glColor3f(1.0f,0.0f,0.0f);						// Set The Color To Red
		glVertex3f( 1.0f, 1.0f, 1.0f);					// Top Right Of The Quad (Front)
		glVertex3f(-1.0f, 1.0f, 1.0f);					// Top Left Of The Quad (Front)
		glVertex3f(-1.0f,-1.0f, 1.0f);					// Bottom Left Of The Quad (Front)
		glVertex3f( 1.0f,-1.0f, 1.0f);					// Bottom Right Of The Quad (Front)
		glColor3f(1.0f,1.0f,0.0f);						// Set The Color To Yellow
		glVertex3f( 1.0f,-1.0f,-1.0f);					// Top Right Of The Quad (Back)
		glVertex3f(-1.0f,-1.0f,-1.0f);					// Top Left Of The Quad (Back)
		glVertex3f(-1.0f, 1.0f,-1.0f);					// Bottom Left Of The Quad (Back)
		glVertex3f( 1.0f, 1.0f,-1.0f);					// Bottom Right Of The Quad (Back)
		glColor3f(0.0f,0.0f,1.0f);						// Set The Color To Blue
		glVertex3f(-1.0f, 1.0f, 1.0f);					// Top Right Of The Quad (Left)
		glVertex3f(-1.0f, 1.0f,-1.0f);					// Top Left Of The Quad (Left)
		glVertex3f(-1.0f,-1.0f,-1.0f);					// Bottom Left Of The Quad (Left)
		glVertex3f(-1.0f,-1.0f, 1.0f);					// Bottom Right Of The Quad (Left)
		glColor3f(1.0f,0.0f,1.0f);						// Set The Color To Violet
		glVertex3f( 1.0f, 1.0f,-1.0f);					// Top Right Of The Quad (Right)
		glVertex3f( 1.0f, 1.0f, 1.0f);					// Top Left Of The Quad (Right)
		glVertex3f( 1.0f,-1.0f, 1.0f);					// Bottom Left Of The Quad (Right)
		glVertex3f( 1.0f,-1.0f,-1.0f);					// Bottom Right Of The Quad (Right)
	glEnd();

	g_rtri += 0.2f;										// Increase The Rotation For The Triangle (NEW)
	g_rquad -= 0.15f;									// Decrease The Rotation For The Quad (NEW)  

	currTime = glutGet(GLUT_ELAPSED_TIME);
	if ((currTime - elapsedTime) > 2000) {
		printf("FPS: %f\n", 1000 * frames / (float) (currTime - elapsedTime));
		elapsedTime = currTime;
		frames = 0;
	}

	++frames;

	// Swap The Buffers To Become Our Rendering Visible
	glutSwapBuffers();
}

void window_reshape_func(int width, int height) {
	glViewport(0, 0, width, height);
	glMatrixMode(GL_PROJECTION);	 // Select The Projection Matrix
	glLoadIdentity();				// Reset The Projection Matrix
	// Calculate The Aspect Ratio And Set The Clipping Volume
	if (height == 0) height = 1;
	gluPerspective(80, (float)width/(float)height, 1.0, 5000.0);
	glMatrixMode(GL_MODELVIEW);	  // Select The Modelview Matrix
	glLoadIdentity();
}

void window_keyboard_func(unsigned char key_value, int x, int y) {
	Window* window = 0;
	switch (key_value) {
		case 27:		// When Escape Is Pressed...
			window = get_window_manager_current_window();
			window_manager_unregister_window(window);
			destroy_window(window);
			break;
		case '+':
			window = get_window_manager_current_window();
			window = create_window("", get_window_width(window),
				get_window_height(window), get_window_x_pos(window) + 25,
				get_window_y_pos(window) + 25, false);
			void setup_new_window(Window* window);
			setup_new_window(window);
			window_manager_register_window(window);
			break;
		default:
			break;
	}
}

void window_special_func(int key_value, int x, int y) {
	Window* window = 0;
	switch (key_value) {
		case GLUT_KEY_F1:
			window = get_window_manager_current_window();
			set_window_fullscreen(window, !get_window_fullscreen(window));
		break;
		default:
		break;
	}
}

void setup_new_window(Window* window) {
	if (window) {
		set_window_init_func(window, window_init_func);
		set_window_display_func(window, window_display_func);
		set_window_idle_func(window, window_display_func);
		set_window_reshape_func(window, window_reshape_func);
		set_window_keyboard_func(window, window_keyboard_func);
		set_window_special_func(window, window_special_func);
	}
}

int main(int argc, char* argv[]) {
	Window* window = 0;
	Window* a_window = 0;

	init_window_manager(argc, argv, GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA);

	window = create_window("", 800, 600, 50, 50, false);
	setup_new_window(window);
	
	a_window = create_window("", 800, 600, 250, 250, true);
	setup_new_window(a_window);

	window_manager_register_window(window);
	window_manager_register_window(a_window);

	window_manager_enable_idle(true);

	window_manager_start_main_loop();

	return 0;
}
